package cn.tannn.cat.file.api.preview;

import cn.tannn.cat.file.api.entity.FileIndexVO;
import cn.tannn.cat.file.sdk.core.OssCache;
import cn.tannn.cat.file.sdk.core.minio.MinioUtils;
import cn.tannn.cat.file.sdk.core.qiniu.QiNiuClient;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import static cn.tannn.cat.file.sdk.enums.StorageDict.MINIO_STORAGE;
import static cn.tannn.cat.file.sdk.enums.StorageDict.QINIU_STORAGE;

/**
 * 预览处理器
 */
public class PreviewUrlProcessor extends JsonSerializer<String>  implements ContextualSerializer {

    private static final Logger log = LoggerFactory.getLogger(PreviewUrlProcessor.class);

    // 环境变量常量
    private static final String ENV_PREVIEW_EXPIRES = "TAN_OSS_PREVIEW_EXPIRES";
    private static final String ENV_PREVIEW_ENABLE = "TAN_OSS_PREVIEW_ENABLE";

    // 默认值
    private static final int DEFAULT_EXPIRES = 86400; // 默认一天
    private static final boolean DEFAULT_ENABLE = true; // 默认启用
    private final boolean enabled;

    private final int expires;
    // 默认一天
    public PreviewUrlProcessor() {
        this.expires = getEnvironmentExpires();
        this.enabled = getEnvironmentEnabled();
    }
    public PreviewUrlProcessor(int annotationExpires) {
        // 环境变量优先级高于注解
        this.expires = getEnvironmentExpires(annotationExpires);
        this.enabled = getEnvironmentEnabled();
    }

    /**
     * 从环境变量获取过期时间，如果没有设置则使用默认值
     */
    private static int getEnvironmentExpires() {
        return getEnvironmentExpires(DEFAULT_EXPIRES);
    }

    /**
     * 从环境变量获取过期时间，如果没有设置则使用fallback值
     */
    private static int getEnvironmentExpires(int fallback) {
        String expiresStr = System.getProperty(ENV_PREVIEW_EXPIRES);
        if (expiresStr == null) {
            expiresStr = System.getenv(ENV_PREVIEW_EXPIRES);
        }

        if (expiresStr != null && !expiresStr.trim().isEmpty()) {
            try {
                int envExpires = Integer.parseInt(expiresStr.trim());
                if (envExpires > 0) {
                    log.debug("使用环境变量设置的预览URL过期时间: {} 秒", envExpires);
                    return envExpires;
                } else {
                    log.warn("环境变量 {} 的值无效 ({}), 使用fallback值: {}", ENV_PREVIEW_EXPIRES, expiresStr, fallback);
                }
            } catch (NumberFormatException e) {
                log.warn("环境变量 {} 格式错误 ({}), 使用fallback值: {}", ENV_PREVIEW_EXPIRES, expiresStr, fallback);
            }
        }

        return fallback;
    }


    /**
     * 从环境变量获取是否启用预览URL功能
     */
    private static boolean getEnvironmentEnabled() {
        String enabledStr = System.getProperty(ENV_PREVIEW_ENABLE);
        if (enabledStr == null) {
            enabledStr = System.getenv(ENV_PREVIEW_ENABLE);
        }

        if (enabledStr != null && !enabledStr.trim().isEmpty()) {
            boolean envEnabled = Boolean.parseBoolean(enabledStr.trim());
            log.debug("使用环境变量设置的预览URL开关: {}", envEnabled);
            return envEnabled;
        }

        return DEFAULT_ENABLE;
    }

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {

        // 如果环境变量禁用了预览功能，直接返回原始值
        if (!this.enabled) {
            log.debug("预览URL功能已通过环境变量禁用");
            gen.writeString(value);
            return;
        }

        Object currentValue = gen.getOutputContext().getCurrentValue();

        if (currentValue instanceof FileIndexVO vo) {


            if (MINIO_STORAGE.getValue().equals(vo.getStorage())) {
                try {
                    String dynamicUrl = MinioUtils.getExpiryObjectUrl(
                            vo.getStorageId(),
                            vo.getBucket(),
                            vo.getPath(),
                            this.expires
                    );
                    gen.writeString(dynamicUrl);
                    return;
                } catch (Exception e) {
                    log.warn("生成MinIO URL失败: {}", e.getMessage());
                }
            }else if (QINIU_STORAGE.getValue().equals(vo.getStorage())){
                try {
                    QiNiuClient qiNiuClient = OssCache.qiNiuClientCache.get(vo.getStorageId());
                    if (qiNiuClient != null) {
                        //去掉地址地址中的特殊符号
                        String urlString = URLEncoder.encode(vo.getPath(), StandardCharsets.UTF_8)
                                .replaceAll("\\+", "%20");
                        String downLoadStr = vo.getUrl().replaceAll(vo.getPath(), urlString);
                        //调用privateDownloadUrl方法生成下载链接,第二个参数可以设置Token的过期时间
                        String dynamicUrl = qiNiuClient.getAuth().privateDownloadUrl(downLoadStr, this.expires);
                        log.debug("生成七牛云预览URL成功, 过期时间: {} 秒", this.expires);
                        gen.writeString(dynamicUrl);
                        return;
                    } else {
                        log.warn("七牛云客户端未找到, storageId: {}", vo.getStorageId());
                    }
                } catch (Exception e) {
                    log.warn("生成七牛云预览URL失败: {}", e.getMessage());
                }
            }else {
                log.debug("暂不支持的存储类型: {}", vo.getStorage());
            }
        }
        // 默认序列化原始值
        gen.writeString(value);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property != null) {
            // 检查方法级注解
            PreviewUrl annotation = null;

            // 尝试从方法获取注解
            if (property.getMember() instanceof AnnotatedMethod method) {
                annotation = method.getAnnotation(PreviewUrl.class);
            }

            // 如果没有从方法获取到，尝试从字段获取
            if (annotation == null) {
                annotation = property.getAnnotation(PreviewUrl.class);
            }

            if (annotation != null) {
                // 传入注解的expires值，但实际会被环境变量覆盖（如果设置了的话）
                return new PreviewUrlProcessor(annotation.expires());
            }
        }
        return this;
    }
}
